#include "stdlib.hpp"
#include <purewell/types.hpp>
#include <purewell/mutex.hpp>

namespace purewell
{

PWMutex::PWMutex(const PWMutexAttribute* pattr)
{
	pthread_mutex_t* pthis(new pthread_mutex_t);
	if ( NULL == pthis ) return;

	if ( 0 != pthread_mutex_init(pthis,
		( NULL != pattr?(pthread_mutexattr_t*)(pattr->getData()):NULL )) )
	{
		delete pthis;
		return;
	}

	m_pData = pthis;
}

PWMutex::~PWMutex()
{
	if ( m_pData )
	{
		pthread_mutex_t* pthis((pthread_mutex_t*)m_pData);
		pthread_mutex_destroy(pthis);
		delete pthis;
		m_pData = NULL;
	}
}

void
PWMutex::release(PWMutex* lock)
{
	delete lock;
}

PWMutex*
PWMutex::create(int type)
{
	PWMutexAttribute* pattr(PWMutexAttribute::create());
	if ( NULL == pattr ) return NULL;

	PWMutex* ret(NULL);

	do
	{
		if ( !pattr->setType(type) ) break;

		ret = new PWMutex(pattr);
		if ( NULL == ret ) break;

		if ( NULL == ret->m_pData )
		{
			delete ret;
			ret = NULL;
		}
	} while (false);

	PWMutexAttribute::release(pattr);

	return ret;
}

PWMutex*
PWMutex::create(const PWMutexAttribute* pattr)
{
	PWMutex* ret(new PWMutex(pattr));
	if ( NULL == ret ) return NULL;
	if ( NULL == ret->m_pData )
	{
		delete ret;
		return NULL;
	}

	return ret;
}

void
PWMutex::lock(void)
{
	pthread_mutex_lock((pthread_mutex_t*)m_pData);
}

void
PWMutex::unlock(void)
{
	pthread_mutex_unlock((pthread_mutex_t*)m_pData);
}

bool
PWMutex::lockTest(void)
{
	return (0 == pthread_mutex_trylock((pthread_mutex_t*)m_pData));
}

bool
PWMutex::lockTimeLimit(size_t msec)
{
	struct timespec ts;
	ts.tv_sec = msec / 1000;
	ts.tv_nsec = (msec % 1000) * 1000;
	return 0 == pthread_mutex_timedlock((pthread_mutex_t*)m_pData, &ts);
}

PWMutexAttribute::PWMutexAttribute()
{
	pthread_mutexattr_t* pthis(new pthread_mutexattr_t);
	if ( NULL == pthis ) return;

	if ( 0 != pthread_mutexattr_init(pthis) )
	{
		delete pthis;
		return;
	}

	m_pData = pthis;
	return;
}

PWMutexAttribute::~PWMutexAttribute()
{
	if ( m_pData )
	{
		pthread_mutexattr_t* pthis((pthread_mutexattr_t*)m_pData);
		pthread_mutexattr_destroy(pthis);
		delete pthis;
		m_pData = NULL;
	}
}

PWMutexAttribute*
PWMutexAttribute::create(void)
{
	PWMutexAttribute* res(new PWMutexAttribute);
	if ( NULL == res )
	{
		return NULL;
	}

	if ( NULL == res->m_pData )
	{
		delete res;
		return NULL;
	}

	return res;
}

void
PWMutexAttribute::release(PWMutexAttribute* obj)
{
	delete obj;
}

bool
PWMutexAttribute::setType(int type)
{
	pthread_mutexattr_t* pthis((pthread_mutexattr_t*)m_pData);
	return 0 == pthread_mutexattr_settype(pthis, type);
}

bool
PWMutexAttribute::getType(int& type) const
{
	pthread_mutexattr_t* pthis((pthread_mutexattr_t*)m_pData);
	return 0 == pthread_mutexattr_gettype(pthis, &type);
}

};//namespace purewell

